package indexv1

import (
	"encoding/json"
	"fmt"
	"lingc/models"
	"lingc/services"
	"lingc/utils"
	"log"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	uuid "github.com/satori/go.uuid"
)

// 定义一个全局的用户连接映射
var (
	userConnections        = make(map[string]*websocket.Conn)
	userChannelConnections = make(map[*websocket.Conn]ChannelData)
	mu                     sync.RWMutex
)

type ChannelData struct {
	//用户类型  member 成员, admin 管理员
	UserType string `json:"user_type"`
	AdminID  uint   `json:"admin_id"`
	//用户id
	UserID    uint   `json:"user_id"`
	UserIDStr string `json:"user_id_str"`
	//消息组ID
	GroupID    uint   `json:"group_id"`
	GroupIDStr string `json:"group_id_str"`
}

// 定义一个自定义的文本消息结构
type MyTextMessage struct {
	//消息id
	ID string `json:"id"`
	//消息类型  login 登录, logout 退出, ping 心跳, text 文本消息,  image 图片消息, video 视频消息, audio 音频消息
	Type string `json:"type"`
	//用户类型  member 成员, admin 管理员
	UserType string `json:"user_type"`
	//客服id
	AdminID string `json:"admin_id"`
	//用户id
	UserID string `json:"user_id"`
	//消息组ID
	GroupID string `json:"group_id"`
	//消息内容
	Content string `json:"content"`
	//用户昵称
	NickName string `json:"nick_name"`
	//头像
	HeadImg string `json:"head_img"`
	//消息分页
	Page int `json:"page"`
}

func WebSocketHandler(c *gin.Context) {
	// 获取WebSocket连接
	wsUpgrader := websocket.Upgrader{
		HandshakeTimeout: time.Second * 10,
		ReadBufferSize:   1024,
		WriteBufferSize:  1024,
		CheckOrigin: func(r *http.Request) bool {
			return true // 允许所有来源
		},
	}
	ws, err := wsUpgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer ws.Close()
	// 添加 defer 语句，在连接关闭时移除用户连接
	defer func() {
		// 清除channel数据
		ClearChannelData(ws)
	}()

	// 处理WebSocket消息
	for {
		messageType, p, err := ws.ReadMessage()
		if err != nil {
			fmt.Println(err)
			break
		}
		switch messageType {
		case websocket.TextMessage:
			disTextMessage(ws, string(p))
			// ws.WriteMessage(websocket.TextMessage, p)
			break
		// case websocket.BinaryMessage:
		// 	fmt.Println("处理二进制消息")
		// 	break
		case websocket.CloseMessage:
			fmt.Println("关闭websocket连接")
			break
		case websocket.PingMessage:
			fmt.Println("处理ping消息")
			ws.WriteMessage(websocket.PongMessage, []byte("ping"))
		// case websocket.PongMessage:
		// 	fmt.Println("处理pong消息")
		// 	ws.WriteMessage(websocket.PongMessage, []byte("pong"))
		default:
			fmt.Printf("未知消息类型: %d\n", messageType)
			break
		}
	}
}

// 单发消息
func SendToMember(userID string, message []byte) error {
	mu.RLock()
	ws, ok := userConnections[userID]
	mu.RUnlock()
	if !ok {
		return fmt.Errorf("用户未连接")
	}
	return ws.WriteMessage(websocket.TextMessage, message)
}

// 发送欢迎消息
func SendToWelcomeMessage(userID uint, adminID uint, group_id uint) error {
	userIDStr := "member" + strconv.Itoa(int(userID))
	mu.RLock()
	ws, ok := userConnections[userIDStr]
	mu.RUnlock()
	if !ok {
		return fmt.Errorf("用户未连接")
	}
	mlist, err := services.NewChatAutoReplyService(utils.MysqlClient).GetChatAutoReplyData(adminID, 0)
	if err != nil {
		return fmt.Errorf("获取欢迎语失败")
	}
	for _, v := range mlist {
		NickName, HeadImg := services.NewChatService(utils.MysqlClient).GetNickId(uint(adminID), "admin")
		closeMessage := MyTextMessage{
			ID:       uuid.NewV4().String(),
			Type:     v.Type,
			UserType: "admin",
			UserID:   fmt.Sprint(adminID),
			GroupID:  fmt.Sprint(group_id),
			AdminID:  fmt.Sprint(adminID),
			Content:  v.Content,
			HeadImg:  HeadImg,
			NickName: NickName,
		}
		jsonMessage, _ := json.Marshal(closeMessage)
		services.NewChatService(utils.MysqlClient).AddChatHistory(models.ChatHistoryCreate{
			GroupID:  group_id,
			UserID:   adminID,
			UserType: "admin",
			Content:  v.Content,
			Type:     v.Type,
			Status:   0,
		})
		ws.WriteMessage(websocket.TextMessage, jsonMessage)
	}
	return nil
}

// 单发通知
func SendToNotify(notifymessage MyTextMessage) error {
	// notifymessage := MyTextMessage{
	// 	ID:       "11dhd378shjhfjdhsj",
	// 	Content:  "{\"type\":\"MESSAGE\",\"title\":\"测试通知\",\"url\":\"https://www.baidu.com\"}",
	// 	UserID:   "1",
	// 	UserType: "admin",
	// }
	sendId := notifymessage.UserType + notifymessage.UserID
	notifymessage.ID = uuid.NewV4().String()
	notifymessage.Type = "notify"
	jsonMessage, _ := json.Marshal(notifymessage)
	return SendToMember(sendId, jsonMessage)
}

// 发送组聊消息列表
func SendToGroup(adminID uint) error {
	group_list, total := services.NewChatService(utils.MysqlClient).GetChatGroup(adminID, 1, 200)
	if total == 0 {
		log.Println("获取群组列表:", total)
		return nil
	}
	for key, group := range group_list {
		group_list[key].Online = IsOnline(group.UserID)
	}

	group_list_json, _ := json.Marshal(group_list)
	notifymessage := MyTextMessage{
		ID:      uuid.NewV4().String(),
		Type:    "group",
		Content: string(group_list_json),
	}
	sendId := "admin" + strconv.Itoa(int(adminID))

	jsonMessage, _ := json.Marshal(notifymessage)
	return SendToMember(sendId, jsonMessage)
}

// 群发消息
func BroadcastMessage(message []byte) {
	mu.RLock()
	defer mu.RUnlock()
	for ws, _ := range userChannelConnections {
		err := ws.WriteMessage(websocket.TextMessage, message)
		if err != nil {
			fmt.Println("群发消息失败:", err)
		}
	}
}

// 处理文本消息
func disTextMessage(ws *websocket.Conn, messageJson string) {
	mytextmessage := MyTextMessage{}
	log.Printf("接收到消息原始: %s", messageJson)
	json.Unmarshal([]byte(messageJson), &mytextmessage)
	switch mytextmessage.Type {
	case "login":
		// 模拟json  {"type":"login","user_type":"admin","groud_id":"","user_id":"1","content":"login"}
		// {"type":"login","user_type":"member","groud_id":"1","user_id":"1","content":"login"}
		// 读取客户端发送的token并验证 并且加入指定聊天组
		token := mytextmessage.Content
		// 验证token（这里假设有一个验证函数）
		userData := utils.ValidateToken(token)
		// log.Printf("用户 %v", userData)
		if userData == nil {
			closeMessage := MyTextMessage{
				ID:      uuid.NewV4().String(),
				Type:    "login",
				Content: "error",
			}
			jsonMessage, _ := json.Marshal(closeMessage)
			ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
			return
		}
		var group_id uint
		var new_group uint
		group_id = 0
		new_group = 0
		if userData.Type == "member" {
			log.Printf("消息 %v", mytextmessage)
			admin_id, _ := strconv.Atoi(mytextmessage.AdminID)
			group_id, new_group = services.NewChatService(utils.MysqlClient).CreateChatGroup(uint(admin_id), userData.ID, userData.Nickame)
			log.Printf("group_id %v", group_id)
			if group_id == 0 {
				closeMessage := MyTextMessage{
					ID:      uuid.NewV4().String(),
					Type:    "login",
					Content: "error",
				}
				jsonMessage, _ := json.Marshal(closeMessage)
				ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
				return
			}
			SetChannelData(ws, userData.Type, uint(userData.ID), group_id, uint(admin_id))
			SendToGroup(uint(admin_id))
			log.Printf("用户 %s 加入群组 %s", userData.Type+fmt.Sprint(userData.ID), group_id)
		} else {
			SetChannelData(ws, userData.Type, uint(userData.ID), group_id, 0)
			SendToGroup(userData.ID)
		}
		closeMessage := MyTextMessage{
			ID:       uuid.NewV4().String(),
			Type:     "login",
			GroupID:  fmt.Sprint(group_id),
			UserID:   fmt.Sprint(userData.ID),
			UserType: userData.Type,
			Content:  "success",
		}
		jsonMessage, _ := json.Marshal(closeMessage)
		// log.Printf("发送消息: %s", jsonMessage)
		// 发送登录成功消息
		ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
		if new_group != 0 {
			if userData.Type == "member" {
				admin_id, _ := strconv.Atoi(mytextmessage.AdminID)
				//发送欢迎语
				SendToWelcomeMessage(userData.ID, uint(admin_id), group_id)
			}
		}
		break
	case "logout":
		// 读取客户端发送的token并验证
		token := mytextmessage.Content
		// 验证token（这里假设有一个验证函数）
		userData := utils.ValidateToken(token)
		if userData == nil {
			closeMessage := MyTextMessage{
				ID:      uuid.NewV4().String(),
				Type:    "logout",
				Content: "error",
			}
			jsonMessage, _ := json.Marshal(closeMessage)
			ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
			return
		}
		// 退出
		mu.Lock()
		// 删除用户连接
		delete(userChannelConnections, ws)
		mu.Unlock()
		closeMessage := MyTextMessage{
			ID:      uuid.NewV4().String(),
			Type:    "logout",
			Content: "success",
		}
		jsonMessage, _ := json.Marshal(closeMessage)
		ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
		ws.Close()
		return
	case "ping":
		closeMessage := MyTextMessage{
			ID:      uuid.NewV4().String(),
			Type:    "ping",
			Content: mytextmessage.Content,
		}
		jsonMessage, _ := json.Marshal(closeMessage)
		ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
		return
	case "group":
		if mytextmessage.UserType == "admin" {
			user_data := GetChannelData(ws)
			admin_id := user_data.UserID
			SendToGroup(uint(admin_id))
			return
		}
		return
	case "read":
		if mytextmessage.UserType == "admin" {
			groud_id, _ := strconv.Atoi(mytextmessage.GroupID)
			user_data := GetChannelData(ws)
			admin_id := user_data.UserID
			services.NewChatService(utils.MysqlClient).ReadMessage(uint(groud_id))
			SendToGroup(uint(admin_id))
			return
		}
		return
	case "msg":
		if mytextmessage.UserType == "member" {
			user_data := GetChannelData(ws)
			closeMessage := MyTextMessage{
				ID:       uuid.NewV4().String(),
				Type:     mytextmessage.Type,
				UserType: mytextmessage.UserType,
				UserID:   fmt.Sprint(user_data.UserID),
				GroupID:  user_data.GroupIDStr,
				Content:  "",
			}
			log.Println("user_data%v", user_data)
			jsonMessage, _ := json.Marshal(closeMessage)
			if user_data.UserIDStr == "" {
				SendToMember("member"+fmt.Sprint(user_data.UserID), []byte(jsonMessage))
			}
			where := fmt.Sprintf("group_id = %d", user_data.GroupID)
			list, total, err := services.NewChatService(utils.MysqlClient).GetChatHistoryList(where, mytextmessage.Page, 30)
			if err != nil {
				SendToMember("member"+fmt.Sprint(user_data.UserID), []byte(jsonMessage))
			}
			msgList := make(map[string]interface{})
			msgList["list"] = list
			msgList["total"] = total
			jsonContent, _ := json.Marshal(msgList)
			closeMessage.Content = string(jsonContent)
			jsonMessage, _ = json.Marshal(closeMessage)
			SendToMember("member"+fmt.Sprint(user_data.UserID), []byte(jsonMessage))
			return
		}
		return
	case "top":
		if mytextmessage.UserType == "admin" {
			user_data := GetChannelData(ws)
			admin_id := user_data.UserID
			groud_id, _ := strconv.Atoi(mytextmessage.GroupID)
			is_top, _ := strconv.Atoi(mytextmessage.Content)
			services.NewChatService(utils.MysqlClient).SetChatGroupTop(uint(groud_id), uint(is_top))
			SendToGroup(uint(admin_id))
			return
		}
		return
	case "text", "image", "video", "audio":
		user_data := GetChannelData(ws)
		if user_data.UserType != "admin" {
			if user_data.GroupIDStr != mytextmessage.GroupID {
				log.Println("发送错误消息 ", mytextmessage.UserType+mytextmessage.GroupID)
				// 发送错误消息
				closeMessage := MyTextMessage{
					ID:      uuid.NewV4().String(),
					Type:    "logout",
					Content: "error",
				}
				jsonMessage, _ := json.Marshal(closeMessage)
				ws.WriteMessage(websocket.TextMessage, []byte(jsonMessage))
				ws.Close()
				return
			}
		}
		// log.Printf("发送消息 %v", mytextmessage)

		group_id := mytextmessage.GroupID
		admin_id, member_id := GetChannelGroup(group_id)
		var status uint8
		var user_id uint
		if mytextmessage.UserType == "admin" {
			status = 1
			user_id = admin_id
		} else {
			status = 0
			user_id = member_id
		}
		NickName, HeadImg := services.NewChatService(utils.MysqlClient).GetNickId(uint(user_id), mytextmessage.UserType)
		closeMessage := MyTextMessage{
			ID:       uuid.NewV4().String(),
			Type:     mytextmessage.Type,
			UserType: mytextmessage.UserType,
			UserID:   fmt.Sprint(member_id),
			GroupID:  group_id,
			AdminID:  fmt.Sprint(admin_id),
			Content:  mytextmessage.Content,
			HeadImg:  HeadImg,
			NickName: NickName,
		}
		jsonMessage, _ := json.Marshal(closeMessage)

		services.NewChatService(utils.MysqlClient).AddChatHistory(models.ChatHistoryCreate{
			GroupID:  uint(utils.StrToInt64(group_id)),
			UserID:   uint(user_id),
			UserType: mytextmessage.UserType,
			Content:  mytextmessage.Content,
			Type:     mytextmessage.Type,
			Status:   status,
		})
		// log.Printf("发送消息: %s", jsonMessage)
		SendToMember("admin"+fmt.Sprint(admin_id), []byte(jsonMessage))
		SendToMember("member"+fmt.Sprint(member_id), []byte(jsonMessage))
		SendToGroup(uint(admin_id))
		return
	}
}

// 判断用户是否在线
func IsOnline(user_id uint) uint {
	userID := "member" + fmt.Sprint(user_id)
	mu.RLock()
	_, ok := userConnections[userID]
	mu.RUnlock()
	if !ok {
		return 0
	}
	return 1
}

// 设置渠道数据
func SetChannelData(ws *websocket.Conn, user_type string, user_id uint, group_id uint, admin_id uint) {

	user_data := ChannelData{
		AdminID:    admin_id,
		UserType:   user_type,
		GroupID:    group_id,
		GroupIDStr: fmt.Sprint(group_id),
		UserID:     0,
		UserIDStr:  "",
	}
	mu.RLock()
	temp_user_data, ok := userChannelConnections[ws]
	if ok {
		user_data = temp_user_data
	}
	mu.RUnlock()
	user_data.UserID = user_id
	user_data.UserIDStr = user_type + fmt.Sprint(user_id)
	mu.Lock()
	userChannelConnections[ws] = user_data
	userConnections[user_type+fmt.Sprint(user_id)] = ws
	mu.Unlock()
}

// 获取用户连接
func GetChannelWs(user_type string, user_id uint) *websocket.Conn {
	mu.RLock()
	ws, ok := userConnections[user_type+fmt.Sprint(user_id)]
	mu.RUnlock()
	if ok {
		return ws
	} else {
		return nil
	}
}

// 获取用户连接
func GetChannelData(ws *websocket.Conn) ChannelData {
	mu.RLock()
	user_data, ok := userChannelConnections[ws]
	mu.RUnlock()
	if ok {
		return user_data
	} else {
		return ChannelData{}
	}
}

// 获取用户组
func GetChannelGroup(group_id string) (uint, uint) {
	group_id_int, _ := strconv.Atoi(group_id)
	ids := services.NewChatService(utils.MysqlClient).GetGroupIds(uint(group_id_int))
	// log.Printf("获取用户组: %v", ids)
	if len(ids) == 0 {
		return 0, 0
	}
	admin_id := ids["admin"]
	member_id := ids["member"]
	return uint(admin_id), uint(member_id)
}

// 清除用户连接
func ClearChannelData(ws *websocket.Conn) {
	mu.Lock()
	user_data, ok := userChannelConnections[ws]
	delete(userChannelConnections, ws)
	mu.Unlock()
	closeAdminId := []uint{}
	if ok {
		if user_data.UserType == "member" {
			closeAdminId = append(closeAdminId, user_data.AdminID)
		}
	}
	if ok {
		mu.Lock()
		delete(userConnections, user_data.UserIDStr)
		mu.Unlock()
	}
	//通知对应客服
	for _, adminID := range closeAdminId {
		log.Println("通知客服:", adminID)
		if adminID != 0 {
			SendToGroup(adminID)
		}
	}
}
